/**
* @file kernel.cpp
*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2024. All Rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#include "acl/acl_rt.h"
#include "runtime/kernel.h"
#include "log_inner.h"
#include "error_codes_inner.h"
#include "toolchain/profiling_manager.h"
#include "toolchain/resource_statistics.h"

aclrtBinary aclrtCreateBinary(const void *data, size_t dataLen)
{
  ACL_ADD_APPLY_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  ACL_LOG_INFO("start to execute aclrtCreateBinary");
  ACL_REQUIRES_NOT_NULL_RET_NULL_INPUT_REPORT(data);

  rtDevBinary_t *binaryDesc = new(std::nothrow) rtDevBinary_t();
  ACL_CHECK_WITH_MESSAGE_AND_RETURN(binaryDesc != nullptr, nullptr, "Allocate memory for binaryDesc failed.");

  binaryDesc->magic = 0U;
  binaryDesc->version = 0U;
  binaryDesc->data = data;
  binaryDesc->length = static_cast<uint64_t>(dataLen);

  ACL_ADD_APPLY_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  return binaryDesc;
}

aclError aclrtDestroyBinary(aclrtBinary binary)
{
  ACL_ADD_RELEASE_TOTAL_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  ACL_LOG_INFO("start to execute aclrtDestroyBinary");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binary);

  delete static_cast<rtDevBinary_t *>(binary);

  ACL_ADD_RELEASE_SUCCESS_COUNT(acl::ACL_STATISTICS_CREATE_DESTROY_ALLOCATOR_BINARY_DESC);
  return ACL_SUCCESS;
}

aclError aclrtBinaryLoad(const aclrtBinary binary, aclrtBinHandle *binHandle)
{
  ACL_ADD_APPLY_TOTAL_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  ACL_LOG_INFO("start to execute aclrtBinaryLoad");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binary);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);
  rtDevBinary_t *bin = static_cast<rtDevBinary_t *>(binary);
  const rtError_t rtErr = rtBinaryLoadWithoutTilingKey(bin->data, bin->length, binHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryLoad failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  ACL_ADD_APPLY_SUCCESS_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  return ACL_SUCCESS;
}

aclError aclrtBinaryUnLoad(aclrtBinHandle binHandle)
{
  ACL_ADD_RELEASE_TOTAL_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  ACL_LOG_INFO("start to execute aclrtBinaryUnLoad");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);

  const rtError_t rtErr = rtBinaryUnLoad(binHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryUnLoad failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  ACL_ADD_RELEASE_SUCCESS_COUNT(acl::ACL_STATISTICS_LOAD_UNLOAD_BINARY);
  return ACL_SUCCESS;
}

aclError aclrtBinaryGetFunction(const aclrtBinHandle binHandle, const char *kernelName, aclrtFuncHandle *funcHandle)
{
  ACL_LOG_INFO("start to execute aclrtBinaryGetFunction");
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(binHandle);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(kernelName);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(funcHandle);

  // currently not support multi kernel, so tilingKey always use 0
  const rtError_t rtErr = rtBinaryGetFunctionByName(binHandle, kernelName, funcHandle);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtBinaryGetFunction failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  return ACL_SUCCESS;
}

aclError aclrtLaunchKernel(aclrtFuncHandle funcHandle, uint32_t blockDim, const void *argsData,
                           size_t argsSize, aclrtStream stream)
{
  ACL_PROFILING_REG(acl::AclProfType::AclrtLaunchKernel);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(funcHandle);
  ACL_REQUIRES_NOT_NULL_WITH_INPUT_REPORT(argsData);

  rtArgsEx_t argsInfo = {};
  argsInfo.args = const_cast<void *>(argsData);
  argsInfo.argsSize = static_cast<uint32_t>(argsSize);
  argsInfo.isNoNeedH2DCopy = 1U;

  const rtError_t rtErr = rtLaunchKernelByFuncHandleV3(funcHandle, blockDim, &argsInfo, stream, nullptr);
  if (rtErr != RT_ERROR_NONE) {
    ACL_LOG_CALL_ERROR("rtLaunchKernelByFuncHandleV3 failed, runtime result = %d.", rtErr);
    return ACL_GET_ERRCODE_RTS(rtErr);
  }

  return ACL_SUCCESS;
}
